/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package elaborate.h2x.transform;

import elaborate.h2x.parser.TransformingModelParserBuilder;
import elaborate.h2x.parser.TransformingModelParserBuilderFactory;
import elaborate.h2x.transform.position.DefaultPositionMapImpl;
import elaborate.h2x.transform.position.IndicatedTransformingNodesPositionerImpl;
import elaborate.h2x.transform.position.LayeredTransformingNodesPositionerImpl;
import elaborate.h2x.transform.position.NaturalTransformingNodesPositionerImpl;
import elaborate.h2x.transform.position.PositionMap;
import elaborate.h2x.transform.position.SchemaBasedTransformingNodesPositionerImpl;
import elaborate.h2x.transform.position.TransformingNodesPositioner;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.w3c.dom.Document;
import org.w3c.dom.Node;

/**
 *
 * @author lendle
 */
public class DefaultTransformerImpl implements Transformer{

    protected TransformingNodesPositioner transformingNodesPositioner=null;

    public DefaultTransformerImpl() {
        transformingNodesPositioner=new LayeredTransformingNodesPositionerImpl();
        ((LayeredTransformingNodesPositionerImpl)transformingNodesPositioner).addTransformingNodesPositioner(new NaturalTransformingNodesPositionerImpl());
        ((LayeredTransformingNodesPositionerImpl)transformingNodesPositioner).addTransformingNodesPositioner(new SchemaBasedTransformingNodesPositionerImpl());
        ((LayeredTransformingNodesPositionerImpl)transformingNodesPositioner).addTransformingNodesPositioner(new IndicatedTransformingNodesPositionerImpl());
    }

    /**
     * Get the value of transformingNodesPositioner
     *
     * @return the value of transformingNodesPositioner
     */
    public TransformingNodesPositioner getTransformingNodesPositioner() {
        return transformingNodesPositioner;
    }

    /**
     * Set the value of transformingNodesPositioner
     *
     * @param transformingNodesPositioner new value of transformingNodesPositioner
     */
    public void setTransformingNodesPositioner(TransformingNodesPositioner transformingNodesPositioner) {
        this.transformingNodesPositioner = transformingNodesPositioner;
    }


    public List<Document> transform(TransformingModel model) throws Exception {
        PositionMap map=new DefaultPositionMapImpl();
        List<TransformingNode> roots=model.getRoots();
        for(TransformingNode root : roots){
            map.getRoots().add(root.getId());
        }
        this.transformingNodesPositioner.determinePositions(model, map);
        DocumentBuilderFactory dbf=DocumentBuilderFactory.newInstance();
        dbf.setNamespaceAware(true);
        DocumentBuilder db=dbf.newDocumentBuilder();

        List<Document> ret=new ArrayList<Document>();

        for(TransformingNodeId root : map.getRoots()){
            Document doc=db.newDocument();
            doc.appendChild(this.constructSubTree(doc, model, map, root));
            ret.add(doc);
        }
        
        return ret;
    }

    protected Node constructSubTree(Document doc, TransformingModel model, PositionMap map, TransformingNodeId nodeId){
        TransformingNode node=model.getNode(nodeId);
        //System.out.println("node="+node.getDef().getNode());
        Node domNode=doc.importNode(node.getDef().getNode(), false);
        List<TransformingNodeId> childNodeIds=map.getOrderedChildList(nodeId);
        //System.out.println("\t"+childNodeIds.size());
        if(childNodeIds!=null){
            for(TransformingNodeId id : childNodeIds){
                domNode.appendChild(this.constructSubTree(doc, model, map, id));
            }
        }
        return domNode;
    }

    public static void main(String [] args) throws Exception{
        TransformingModelParserBuilderFactory tmf=TransformingModelParserBuilderFactory.newInstance();
        TransformingModelParserBuilder tmb=tmf.newTransformingModelParserBuilder();

        DocumentBuilderFactory dbf=DocumentBuilderFactory.newInstance();
        dbf.setNamespaceAware(true);
        DocumentBuilder db=dbf.newDocumentBuilder();
        Document doc=db.parse(new File("example_xml.xml"));

        TransformingModel model=tmb.newTransformingModelParser().parse(doc);

        Transformer transformer=new DefaultTransformerImpl();
        List<Document> newDocs=transformer.transform(model);

        javax.xml.transform.Transformer tf=TransformerFactory.newInstance().newTransformer();
        for(Document newDoc : newDocs){
            tf.transform(new DOMSource(newDoc), new StreamResult(System.out));
        }
    }
}
